/*
 * @Author: xiaosihan 
 * @Date: 2023-12-19 23:04:12 
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-03-10 10:25:55
 */

import homeStore from "@views/home/homeStore";
import { autorun } from "mobx";
import { Euler, Group, InstancedBufferAttribute, InstancedMesh, Matrix4, Quaternion, Vector3, BufferAttribute } from "three";
import threeUtils from "three-base/threeUtils";
import { degToRad } from "three/src/math/MathUtils";
import floorModalGLB from "./floorModal.glb?url";
import threeLoader from "three-base/threeLoader";
import InstancedGroupMesh from "../../InstancedGroupMesh";
import MeshBase from "../../MeshBase/MeshBase";

// 楼层组
export default class FloorGroup extends Group {
    constructor() {
        super(); -
            this.loadModel();
    }

    static _position: Vector3 = new Vector3();
    static _scale: Vector3 = new Vector3(1, 1, 1);
    static _rotation: Euler = new Euler();
    static _Quaternion: Quaternion = new Quaternion();
    static _Matrix4: Matrix4 = new Matrix4();

    // 楼层数量
    floorNum = 1;
    setFloorNum(floorNum: number, windowNum: { east: number; south: number; }) {
        this.floorNum = floorNum;
        const { floorHeight } = homeStore;
        this.updataInstanceMesh(this.floorNum, windowNum, floorHeight);
    }

    // 监控模型的实例对象
    monitorInstanceMesh!: InstancedGroupMesh;

    //原网格对象
    originAttributeMap = new Map<string, BufferAttribute>();

    // 是否加载完成
    loaded = false;

    // 加载楼层模型
    loadModel() {
        const meshBase = new MeshBase(floorModalGLB);
        meshBase.addEventListener("loaded", () => {
            // 清空原原网格缓存
            this.originAttributeMap.clear();
            meshBase.traverseMesh(mesh => {
                const position = mesh.geometry.getAttribute("position") as BufferAttribute;
                this.originAttributeMap.set(mesh.name, position);
                mesh.geometry = mesh.geometry.clone();
                mesh.material.map && (mesh.material.map.anisotropy = threeLoader.anisotropy);
            });

            meshBase.rotateY(degToRad(-90));
            threeUtils.scaleTo(meshBase, 0.3, ["y"]);
            threeUtils.center(meshBase);
            threeUtils.alignBottom(meshBase);
            const size = threeUtils.getSize(meshBase);
            homeStore.setFloorHeight(size.y);
            this.monitorInstanceMesh = new InstancedGroupMesh(meshBase, 0);
            this.add(this.monitorInstanceMesh);
            homeStore.setFloorNum(5);

            this.loaded = true;
        });
    }

    // 更新实例矩阵
    async updataInstanceMesh(floorNum: number, windowNum: { east: number; south: number; }, floorHeight: number) {
        //等待模型加载完成
        while (!this.monitorInstanceMesh) {
            await new Promise(resolve => setTimeout(resolve, 200));
        }
        // 如果实例数量有改变就重新创建实例矩阵
        if ((floorNum + 3) !== this.monitorInstanceMesh.count) {
            this.monitorInstanceMesh.count = (floorNum + 3);
            this.monitorInstanceMesh.children.map((instanceMesh: InstancedMesh) => {
                instanceMesh.count = (floorNum + 3);
                instanceMesh.instanceMatrix = new InstancedBufferAttribute(new Float32Array((floorNum + 3) * 16), 16);
            });
        }

        for (let i = 0; i < (floorNum + 4); i++) {
            // 设置矩阵
            if (i < 2) {
                FloorGroup._position.set(0, floorHeight * (i - 1), 0);
            } else {
                FloorGroup._position.set(0, floorHeight * i, 0);
            }
            FloorGroup._Quaternion.setFromEuler(FloorGroup._rotation);
            FloorGroup._Matrix4.compose(FloorGroup._position, FloorGroup._Quaternion, FloorGroup._scale);
            this.monitorInstanceMesh.setMatrixAt(i, FloorGroup._Matrix4);
        }

        // 更具窗户的数量计算网格的偏移量
        const offset = {
            east: (8 - Math.max(5, windowNum.east)) * 0.002,
            south: (8 - Math.max(5, windowNum.south)) * 0.002,
        }

        //更具窗户数更新网格
        this.monitorInstanceMesh.children.map(instancedMesh => {
            const originPosition = this.originAttributeMap.get(instancedMesh.name)!;
            const position = instancedMesh.geometry.getAttribute("position")!;
            for (let i = 0; i < originPosition.count; i++) {
                if (originPosition.getX(i) >= 0) {
                    position.setX(i, originPosition.getX(i) - offset.south);
                } else if (originPosition.getX(i) <= 0) {
                    position.setX(i, originPosition.getX(i) + offset.south);

                }

                if (originPosition.getZ(i) >= 0) {
                    position.setZ(i, originPosition.getZ(i) - offset.east);
                } else if (originPosition.getZ(i) <= 0) {
                    position.setZ(i, originPosition.getZ(i) + offset.east);
                }
            }
            position.needsUpdate = true;
            instancedMesh.geometry.computeBoundingBox();
        });

    }

}